/** 条件判断 三元运算符 */


/** 这是一个普通obj */
interface Animal {
    live(): void;
}

/** 这是一个方法 */
interface B<T> {
    (): T;
}

const a: Animal = {
    live: () => null,
};

const b: B<string> = () => ""

interface A1 extends Animal {
    woof(): void;
}
// extends 判断和 三元运算符
type A2 = A1 extends Animal ? true : false; // type A2 = true
type A3 = RegExp extends Animal ? true : false; // type A3 = false

// ------------------------------------------------
interface NameLabel {
    name: string;
}

interface IdLabel {
    id: number
}

/** 注意
 * 这里的两个extends有本质的区别
 * 第一个extends T extends String ｜ number：是类型约束表示这里的T只能是这两个Union；叫条件约束
 * 第二个extends T extends String；是类型判断。用来判断具体T是什么类型
 */
type NameOrId<T extends String | number> = T extends String ? NameLabel : IdLabel;
type Name = NameOrId<string>; // type Name = NameLabel
type Id = NameOrId<number> // type Id = IdLabel

function createLabel<T extends string | number>(): NameOrId<T> {
    throw "123";
}
let a11 = createLabel<string>(); // let a11: NameLabel
let a22 = createLabel<number>(); // let a11: IdLabel
let j = (Math.random() == 0.5) ? "" : 23;
let a33 = createLabel<j>(); // let a33: NameLabel | IdLabel


/** 条件类型约束 */
// type MessageOf<T> = T["message"]; // 这里会报错，因为T这个类型不一定有message这个key。改成下面这样
type MessageOf<T extends { message: unknown }> = T["message"];
type M = MessageOf<{ message: number }>; // type M = number;
// 请再次比较下上下两个的区别
type MessgeOf2<T> = T extends { kind: unknown } ? T["kind"] : never;
interface Email {kind: string;}
interface Dog {bark(): void;}
type MM = MessgeOf2<Email>; // type MM = string
type MMM = MessgeOf2<Dog> // type MMM = never

 
/** 平铺开 */
type Flatten<T> = T extends any[] ? T[number] : T; // 这里的T[number] 是之前学过的下标类型取之
type Str = Flatten<string[]> // type Str = string;
type Num = Flatten<number> // type Num = number


/** infer */
// 针对上面Flatten还可以通过infer进行优化
type Flatten1<T> = T extends Array<infer Item> ? Item : T;

type Str1 = Flatten1<string | number[]> // type Str = string; 效果是一样的，但是更优雅
type Num1 = Flatten1<number> // type Num = number


type GetReturnType<T> = T extends (...arg: never[]) => infer Return ? Return : T;
type R1 = GetReturnType<() => number>; // type R1 = number;
type R2 = GetReturnType<string>; // type R2 = string;



/** Distributive Conditional Types 分配条件类型 */
type ToArray<T> = T extends any ? T[] : never;
type Ar = ToArray<string | number>; // type Ar = string[] | number[];注意：这里string[] | number[] 和 (string | number[] 是有一个本质的区别的！！！！！！！！！！！！
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never; // 通过[T] extends [any] 把类型展开就可以了。没啥技巧，背下来吧·
type Ar2 = ToArrayNonDist<string | number>; // type Ar2 = (string | number)[] 



type PickKind<T extends { kind: unknown}> = {
    [key in keyof T as key extends "kind" ? "kind" : never]: T[key];
}

type MMMMMM = PickKind<{key: number; kind: string}>
const mm: MMMMMM = {
    // key: 123,
    kind: "123"
}












